/*
 * @Author: 晴鸢. 3013433857@qq.com
 * @Date: 2025-09-18 14:49:11
 * @LastEditors: 晴鸢. 3013433857@qq.com
 * @LastEditTime: 2025-09-21 13:10:38
 * @FilePath: /Learn/thread/mythread.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <iostream>
#include <vector>
#include <pthread.h>
#include <cstring>
#include "LockGuard.hpp"
#include <unistd.h>
using namespace std;
#define NUM 3

int val = 100; // 共享区
int *p = nullptr;
__thread int num = 0;
struct threaddata
{
    string threadname;
};

string toHex(pthread_t tid)
{
    char buffer[128];
    snprintf(buffer, sizeof(buffer), "0x%x", tid);
    return buffer;
}

// 不同线程享有独立的栈
void *threadRoutine(void *args)
{
    int test_i = 0;
    threaddata *td = static_cast<threaddata *>(args);
    int i = 0;
    num = pthread_self();
    if (td->threadname == "thread-2")
        p = &test_i;
    while (i < 10)
    {
        //                            返回线程的id
        cout << "pid:" << getpid() << "," << toHex(num) << ",threadname:" << td->threadname << ",test_i:" << test_i
             << ",&test_i" << toHex((pthread_t)&test_i) << endl;
        i++;
        test_i++;
        sleep(1);
    }
    delete td;
    return nullptr;
}

void Initthreaddata(threaddata *td, int num)
{
    td->threadname = "thread-" + to_string(num);
}
// 多线程的创建
void test1()
{
    vector<pthread_t> tids;
    for (int i = 0; i < NUM; i++)
    {
        pthread_t tid;
        threaddata *td = new threaddata; // 直接指向堆空间
        Initthreaddata(td, i);

        pthread_create(&tid, nullptr, threadRoutine, td);
        tids.push_back(tid);
        // sleep(1);
    }

    sleep(1);
    // 主线程可以拿到子线程中的内容
    cout << "main thread get a thread local value,val:"
         << *p << ",&val:" << p << endl;
    for (int i = 0; i < tids.size(); i++)
    {
        pthread_join(tids[i], nullptr);
    }
}

#define N 4
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int tickets = 1000; // 用多线程，模拟一轮抢票
class threadData
{
public:
    threadData(int num /*,pthread_mutex_t*mutex*/)
    {
        threadname = "thread-" + to_string(num);
        // lock=mutex;
    }

public:
    string threadname;
    // pthread_mutex_t*lock;
};
/*
void* getTicket(void*args)
{
    threadData*td=static_cast<threadData*>(args);
    const char*name=td->threadname.c_str();
    while(1)
    {
        //申请锁成功后才能往后执行，否则阻塞等待
        pthread_mutex_lock(&lock);
        if(tickets>0)
        {
            usleep(1000);
            printf("%s,get a ticket:%d\n",name,tickets);
            tickets--;
            //pthread_mutex_unlock(&lock);
        }
        else
        {
            //pthread_mutex_unlock(&lock);
            break;
        }
        usleep(10);//多线程抢到票之后还要执行得到票之后的后续操作，usleep模拟
    }
    printf("%s ... quit\n",name);
    return nullptr;
}
*/
void *getTicket(void *args)
{
    threadData *td = static_cast<threadData *>(args);
    const char *name = td->threadname.c_str();
    while (1)
    {
        {
            // 申请锁成功后才能往后执行，否则阻塞等待
            LockGuard lockguard(&lock); // 临时的 LockGuard对象
            // 构造时自动加锁，析构时自动解锁
            if (tickets > 0)
            {
                usleep(1000);
                printf("%s,get a ticket:%d\n", name, tickets);
                tickets--;
            }
            else
                break;
        }
        usleep(10); // 多线程抢到票之后还要执行得到票之后的后续操作，usleep模拟
    }
    printf("%s ... quit\n", name);
    return nullptr;
}

void test2()
{
    // pthread_mutex_init(&lock,nullptr);

    vector<pthread_t> tids;            // 线程的tid
    vector<threadData *> thread_datas; // 线程名
    for (int i = 1; i <= N; i++)
    {
        pthread_t tid;
        threadData *td = new threadData(i /*,&lock*/);
        thread_datas.push_back(td);
        pthread_create(&tid, nullptr, getTicket, thread_datas[i - 1]);
        tids.push_back(tid);
    }

    for (auto thread : tids)
    {
        pthread_join(thread, nullptr);
    }
    for (auto td : thread_datas)
    {
        delete td;
    }
    // pthread_mutex_destroy(&lock);
}
int main()
{
    // test1();
    test2();
    return 0;
}